home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / Amiga_Mail_Vol1 / SerParCIA / SoftIntTimer < prev    next >
Encoding:
Text File  |  1999-10-27  |  9.7 KB  |  308 lines

  1. (c)  Copyright 1989-1999 Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice, and 
  3. is provided "as is" without warranty of any kind, either expressed or implied.  
  4. The entire risk as to the use of this information is assumed by the user.
  5.  
  6.  
  7.  
  8.                 SoftInt MsgPorts and the Timer Device
  9.  
  10.                      Carolyn Scheppner - CATS
  11.  
  12.  
  13.      
  14. Most Amiga programmers are familiar with the PA_SIGNAL type of
  15. Exec MsgPort which signals a task when a message is received.  This
  16. is the type of MsgPort that Intuition provides for IDCMP, and also
  17. the type commonly used for Exec device IO.  The amiga.lib functions
  18. CreatePort() and DeletePort() are for PA_SIGNAL ports.
  19.  
  20. A less familiar type of Exec MsgPort is the PA_SOFTINT port.
  21. PA_SOFTINT ports cause a software interrupt when a message is received, 
  22. rather than signalling a task.  Software interrupts execute at a priority 
  23. lower than hardware interrupts but higher than tasks - that is, a software 
  24. interrupt will pre-empt even a running task.  
  25.  
  26. For time-sensitive applications the timer.device will give more precise
  27. timings with a PA_SOFTINT port than with a PA_SIGNAL port.  This is because 
  28. the PA_SIGNAL port typically requires applications to Wait() for the device 
  29. to respond either directly, or indirectly with a DoIO() call.  Such a Wait()
  30. will switch out the calling task until the device has responded at which 
  31. time the calling task will be placed in the ready queue awaiting its turn
  32. to run.  Under heavy multi-tasking loads, this extra overhead can cause
  33. additional delay in interval timings leading many people to believe that
  34. the timer.device is not accurate.  In reality, the timer.device can provide
  35. accurate timing even with intervals occuring several times per video
  36. frame.  The trick is to eliminate the task-switching overhead by using a
  37. PA_SOFTINT port.
  38.  
  39. This can provide timings which are more consistent under heavy multi-tasking 
  40. loads.  This technique could be useful for an application that needs to poll 
  41. or control external hardware at regular intervals, and can also be used for 
  42. simple incrementing of counters or program timers.  
  43.  
  44. Keep in mind that your software interrupt code should be kept as short and 
  45. quick as possible, so that system and application tasks can get the time 
  46. they need.  Note that if a Disable() is in effect, no interrupts will be 
  47. generated.  If a Forbid() is in effect interrupts will still run normally. 
  48.  
  49. The audio chapter of Addison-Wesley's "ROM Kernel Manual: Libraries 
  50. and Devices" gives an audio device example which demonstrates the use of
  51. a PA_SOFTINT port for the automatic manipulation of audio samples.
  52. The example listed here, TimerSoftInt.c, demonstrates how a PA_SOFTINT
  53. port can be used with the timer.device to produce software interrupts
  54. several times per frame.  TimerSoftInt changes the screen color to display 
  55. when and how often the timer software interrupt code is being executed.
  56. By adjusting the value passed to TimerSoftInt, you can find an interval
  57. which will cause the timer interrupts to occur at approximately the
  58. same vertical position each frame, allowing you to clearly see and test
  59. the consistency of the timing under different multi-tasking loads such as
  60. when running a compiler, for example.
  61.  
  62.   
  63. IMPORTANT
  64.  
  65. Do not BeginIO() to any device other than timer or audio from within a 
  66. software or hardware interrupt.  The BeginIO() code of other devices may 
  67. allocate memory, Wait(), or perform other functions which are illegal or 
  68. dangerous during interrupts.  
  69.  
  70. The example below directly accesses the background color register so you
  71. can "see" when a timer interrupt occurs.  An application should NEVER do
  72. this.  Use direct access to Amiga hardware registers for debugging or 
  73. demonstration purposes ONLY, as is the case here.
  74.  
  75.  
  76. --------------------------------------------------------------------------
  77. /*
  78.  * TimerSoftInt.c  -  C. Scheppner  C.A.T.S.  02/89
  79.  * Copyright 1989-1999 Amiga, Inc.   All Rights Reserved
  80.  *
  81.  * Demonstrates use of the timer.device with a PA_SOFTINT MsgPort
  82.  * for applications that need to do processing on a regular basis,
  83.  * several times per frame, in a multi-tasking environment.
  84.  */
  85.  
  86. #include "exec/types.h"
  87. #include "exec/interrupts.h"
  88. #include "exec/memory.h"
  89. #include "devices/timer.h"
  90. #include "libraries/dos.h"
  91. #include "hardware/custom.h"
  92.  
  93. extern struct Custom custom;
  94.  
  95. #define RED_CT     18
  96. #define MIC_DELAY  2500
  97. #define MIN_DELAY  1200
  98.  
  99. extern VOID *tsoftcode();  /* our timer softint code */
  100.  
  101. struct Interrupt    *tint = NULL;
  102. struct timerequest  *treq = NULL;
  103. struct MsgPort      *tport = NULL;
  104.  
  105. BOOL OpenedTimer = FALSE;
  106.  
  107. /* Global variables shared with the softint code
  108.  * If our tsoftcode was in assembler, we could use is_Data
  109.  * pointer instead to tell softint code where shared data is
  110.  */
  111. #define OFF 0
  112. #define ON  1
  113. #define STOPPED 2
  114.  
  115. ULONG redct, micdelay;
  116.  
  117. BOOL SFlag=OFF;
  118.  
  119. char tportname[] = "CAS_CBM_timer_softint";
  120. char cprt[] =
  121.   "Copyright (c) 1989-1999 Amiga, Inc. All Rights Reserved";
  122.  
  123.  
  124. main(argc,argv)
  125. int  argc;
  126. char **argv;
  127.    {
  128.    if(!argc)  exit(RETURN_FAIL);  /* CLI only example...Uses printf */
  129.  
  130.    redct = RED_CT;
  131.    micdelay = MIC_DELAY;
  132.    if(argc>1)
  133.       {
  134.       if(argv[1][0]=='?') cleanexit("TimerSoftInt [mdelay]",RETURN_OK);
  135.       else micdelay=atoi(argv[1]);
  136.       if(micdelay < MIN_DELAY)
  137.          {
  138.          micdelay = MIN_DELAY;
  139.          printf("Delay set to example minimum of %ld\n",MIN_DELAY);
  140.          }
  141.       }
  142.  
  143.    /* Allocate our MsgPort and Interrupt structures
  144.     * Since we can't use CreatePort, we'll build the port ourselves.
  145.     * Create Port creates a PA_SIGNAL and allocs a signal.
  146.     * We want a PA_SOFTINT port;
  147.     */
  148.  
  149.    if(!(tport = (struct MsgPort *)
  150.        AllocMem(sizeof(struct MsgPort),MEMF_PUBLIC|MEMF_CLEAR)))
  151.            cleanexit("Can't allocmem msgport",RETURN_FAIL);
  152.  
  153.    if(!(tint = (struct Interrupt *)
  154.        AllocMem(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_CLEAR)))
  155.            cleanexit("Can't allocmem interrupt",RETURN_FAIL);
  156.  
  157.  
  158.    /* Set up the interrupt structure.
  159.     * Note that we are priority 0.  Software interrupts may only be
  160.     * priority -32, -16, 0, +16, or +32.  Also note that the
  161.     * correct node type for a software interrupt is NT_INTERRUPT.
  162.     * (NT_SOFTINT is an internal flag of Exec's)
  163.     */
  164.    tint->is_Code = (VOID (*)())tsoftcode;  /* Our softint routine */
  165.    tint->is_Node.ln_Type = NT_INTERRUPT;
  166.    tint->is_Node.ln_Pri = 0;
  167.  
  168.    /* Set up the PA_SOFTINT msgport */
  169.    tport->mp_Node.ln_Type = NT_MSGPORT;
  170.    tport->mp_Node.ln_Name = (char *)tportname;
  171.    tport->mp_Flags = PA_SOFTINT;
  172.    tport->mp_SigTask = (struct Task *)tint;  /* Ptr to interrupt struct */
  173.  
  174.    /* Not using CreatePort, so we must add the port ourselves */
  175.    AddPort(tport);
  176.  
  177.    /* Now Create the IO request */
  178.    if(!(treq=(struct timerequest *)
  179.       CreateExtIO(tport,sizeof(struct timerequest))))
  180.          cleanexit("Can't create ioreq", RETURN_FAIL);
  181.  
  182.    /* Open the timer device - Note 0 return means success */
  183.    if(OpenDevice("timer.device",UNIT_MICROHZ,treq,0))
  184.       cleanexit("Can't open timer device",RETURN_FAIL);
  185.  
  186.    OpenedTimer = TRUE;    /* Flag for closing in cleanup */
  187.  
  188.    /* Now, let's do something with it */
  189.    SFlag = ON;
  190.    begintr(treq);         /* Prime the pump with first timer request */
  191.  
  192.    printf("Started timer softint.  Press CTRL/C to exit...");
  193.    Wait(SIGBREAKF_CTRL_C);
  194.    printf("\nReceived CTRL_C... Turning off softint\n");
  195.    
  196.    SFlag = OFF;
  197.    while(SFlag != STOPPED)  Delay(10);
  198.  
  199.    cleanup();
  200.    exit(RETURN_OK);
  201.    }
  202.  
  203.  
  204. /* Routine called as software interrupt */
  205. VOID *tsoftcode()
  206.    {
  207.    struct timerequest *tr;
  208.    ULONG de;
  209.  
  210.    /* Remove our message from our port */
  211.    tr = (struct timerequest *)GetMsg(tport);
  212.  
  213.    /* If main hasn't flagged us to stop, keep the ball rolling */
  214.    if((tr)&&(SFlag==ON))
  215.       {
  216.       /* Hit background color register for demonstration purposes
  217.        * and send the timer request out again.
  218.        * IMPORTANT: This self-perpetuating technique of calling
  219.        * BeginIO during a software interrupt may only be used with
  220.        * the audio and timer device.
  221.        */
  222.       custom.color[0] = 0x0FF0;
  223.       begintr(tr);
  224.  
  225.       /* Then hit the background color register again to show the
  226.        * the duration of the rest of our softint routine (for/next).
  227.        * Hitting registers like this is for debugging only!
  228.        */
  229.       custom.color[0] = 0x0F00;
  230.       for(de=0; de < redct; de++);  /* Our do-nothing softint routine */
  231.  
  232.       /* Back to default screen color */
  233.       custom.color[0] = 0x005A;
  234.       }
  235.  
  236.    /* Else flag main we have indeed stopped */
  237.    else(SFlag=STOPPED);
  238.    return(0);
  239.    }
  240.  
  241.  
  242. /* begintr(tr)
  243.  * Sets up and sends off timer request.
  244.  * IMPORTANT: Do not BeginIO to any device other than timer or audio
  245.  * from within a software or hardware interrupt.  The BeginIO code
  246.  * of other devices may allocate memory, wait, or perform other
  247.  * functions which are illegal or dangerous during interrupts.
  248.  */
  249. begintr(tr)
  250. struct timerequest *tr;
  251.    {
  252.    /* Set up the timer command */
  253.    tr->tr_node.io_Command = TR_ADDREQUEST;
  254.    tr->tr_time.tv_micro = micdelay;
  255.    BeginIO(tr);
  256.    }
  257.  
  258. /* Prints message if any, cleans up, and exits */
  259. cleanexit(s,n)
  260. UBYTE *s;
  261. int n;
  262.    {
  263.    if(*s)  printf("%s\n",s);
  264.    cleanup();
  265.    exit(n);
  266.    }
  267.  
  268. /* Close/deallocate everything opened/allocated */
  269. cleanup()
  270.    {
  271.    if(OpenedTimer)  CloseDevice(treq);
  272.    if(treq)         DeleteExtIO(treq);
  273.    if(tport)
  274.       {
  275.       RemPort(tport);
  276.       FreeMem(tport,sizeof(struct timerequest));
  277.       }
  278.    if(tint)  FreeMem(tint, sizeof(struct Interrupt));
  279.    }
  280.  
  281.  
  282. atoi( s )
  283. char *s;
  284.    {
  285.    int num = 0;
  286.    int neg = 0;
  287.  
  288.    if( *s == '+' ) s++;
  289.    else if( *s == '-' )
  290.       {
  291.       neg = 1;
  292.       s++;
  293.       }
  294.  
  295.    while( *s >= '0' && *s <= '9' )
  296.       {
  297.       num = num * 10 + *s++ - '0';
  298.       }
  299.    if( neg ) return( - num );
  300.    return( num );
  301.    }
  302.  
  303.  
  304. /* end */
  305.  
  306.  
  307.  
  308.